

#include <chrono>
#include <iostream>
#include <future>
#include <iterator>
#include <iomanip>
#include <string_view>
#include <experimental/coroutine>

#include <ppltasks.h>
#include <pplawait.h>

#include "catch.hpp"

#include <windows.h>


#ifdef _RESUMABLE_FUNCTIONS_SUPPORTED

template<class Rep, class Period>
auto operator co_await(std::chrono::duration< Rep, Period > interval)
{
	class awaiter
	{
		static void CALLBACK TimerCallback(PTP_CALLBACK_INSTANCE, void *Context, PTP_TIMER)
		{
			std::experimental::coroutine_handle<>::from_address(Context)();
		}
		PTP_TIMER timer = nullptr;
		std::chrono::system_clock::duration duration;
	public:
		explicit awaiter(std::chrono::system_clock::duration d) : duration(d) {}
		bool await_ready() const { return duration.count() <= 0; }
		bool await_suspend(std::experimental::coroutine_handle<> resume_cb)
		{
			int64_t relative_count = -duration.count();
			timer = CreateThreadpoolTimer(&TimerCallback, resume_cb.address(), nullptr);
			SetThreadpoolTimer(timer, (PFILETIME)&relative_count, 0, 0);
			return timer != 0;
		}
		void await_resume() {}
		~awaiter() { if(timer) CloseThreadpoolTimer(timer); }
	};

	return awaiter(interval);
}

#endif


class Test3
{
public:
	std::string str = "Hi!!!!";

	~Test3()
	{
	}

	std::future<void> fireAndForget(std::shared_ptr<Test3> r)
	{
		co_await std::async(std::launch::async, []{
			std::this_thread::sleep_for(std::chrono::milliseconds(200));;
		}); //

		std::cout << str << std::endl;
	}
};


TEST_CASE("coroutine")
{

	{
		auto test = std::make_shared<Test3>();
		test->fireAndForget(test);
	}
}
